/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package flowvis;

import flowsimulation.FlowSimulator;
import gui.EllipsoidRendererPanel;
import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;

/**
 *
 * @author waldo
 */
public class EllipsoidRenderer extends Renderer {
    
    private static boolean VISIBLE = false;
    // Light parameters.
    private final float SHINE_IN_ALL_DIRECTIONS = 1;
    private final float[] lPosition = {0, 0, 1, SHINE_IN_ALL_DIRECTIONS};
    private final float[] lColorSpecular = {0.85f, 0.85f, 0.85f, 1f};
    private final float[] lColorAmbient = {0.3f, 0.3f, 0.3f, 1f};
    private final float RADIUS = 1f;
    private static int SLICES;
    private static int STACKS;
    private static int rotatePlaneDegrees = 0;
    //private static boolean one_time = true;
    
    public static int nbX = 64;
    public static int nbY = 64;
    public static double[][][] originalValues = new double [64][64][4];
    public static int DIM = 64;
    
    
    //Parameters of the Panel
    private static float vec_scale = 100; // scaling factor = default value
    /*vector field : true for force, false for velocity*/
    private static boolean vectorField = false;
    EllipsoidRendererPanel panel;
    private static int scalar_col;
    private static boolean enableClamping = true;
    
    public EllipsoidRenderer( FlowSimulator sim ){
        super(sim);
        panel = new EllipsoidRendererPanel( this );
    }
    
    public EllipsoidRendererPanel getPanel() { return panel; }
    public static void setScale(float s) { vec_scale = s; }
    public static float getScale() { return vec_scale; }
    public static void setVectorField(boolean b) { vectorField = b; }
    public static boolean getVectorField() { return vectorField; }
    public static int getColor(){ return scalar_col; }
    public static void setColor(int c) { scalar_col = c; }
    public static void setVisible( boolean visible ){ VISIBLE = visible; }
    public static boolean getVisible(){ return VISIBLE; }
    public static void setNbX (int x) {nbX = x;}
    public static void setNbY (int y) {nbY = y;}
    public static void setRotatePlaneGrades(int grades){rotatePlaneDegrees = grades;}
    public static void enableClamping( boolean b ){ enableClamping=b; }
    
    /**
     * 
     * @param gl
     * @param x
     * @param y 
     */
    float[] direction_to_color(GL gl, float x, float y/*, int method*/){
        float value = (float)Math.sqrt(x*x+y*y);
        if(!vectorField)
            value=(value-VelocityRenderer.MIN_USER_VELOCITY)/(VelocityRenderer.MAX_USER_VELOCITY-VelocityRenderer.MIN_USER_VELOCITY);
         else
            value=(value-ForceRenderer.MIN_USER_FORCE)/(ForceRenderer.MAX_USER_FORCE-ForceRenderer.MIN_USER_FORCE);
        float[] color = new float[3];
        switch( scalar_col ){
            case(0): //White
                color[0] = color[1] = color[2] = 1;
                break;
            case(1): //grey scale
                ColorMap.blackwhite(value, color, false, false);
                break;
            case(2): //rainbow
                ColorMap.rainbow(value, color, false, false);
                break;
            case(3): //blackbody
                ColorMap.blackbody(value, color, false, false);
                break;
            case(4): //temperature
                ColorMap.temperature(value, color, false, false);
                break;
            case(5): //green to red
                ColorMap.green2red(value, color, false, false);
                break;
        }
        return color;
    }
    
    /* Function to create the array with the x and y original position and their associated magnitude values */
    public void arrayGeneration(){
        double[] vx;// = simulator.getVelocityX();
        double[] vy;// = simulator.getVelocityY();
        double own = getWinWidth() / (double) (DIM);   // Grid cell width
        double ohn = getWinHeight() / (double) (DIM);  // Grid cell heigh
        
        if(!vectorField)
        {
            vx = simulator.getVelocityX();
            vy = simulator.getVelocityY();
        }
        else// if (vectorField)
        {
            vx = simulator.getForceX();
            vy = simulator.getForceY();
        }
        for (int i = 0; i < DIM; i++) {
            for (int j = 0; j < DIM; j++) {
                originalValues[i][j][0] = own * i+own;
                originalValues[i][j][1] = ohn * j + ohn;
                int idx = (j * DIM) + i;
                originalValues[i][j][2] = vx[idx];
                originalValues[i][j][3] = vy[idx];
                
            }
        }
        
    }
    
    public static double[] nearestNeighbour(double[][][]originalValues, double x, double y) {
        double[] magnitude = new double [2];
        double newX = 10;
        double newY = 10;
        int finalX = 0;
        int finalY = 0;
       
        for (int i = 0; i < DIM; i++) {
           if(Math.abs(originalValues[i][0][0] - x) < newX )
           {
               newX = Math.abs(originalValues[i][0][0] - x);
               finalX = i;
           }
        }

       for (int i = 0; i < DIM; i++) {
           if(Math.abs(originalValues[0][i][1] - y) < newY )
           {
               newY = Math.abs(originalValues[0][i][1] - y);
              finalY = i;
           }
        }
       
       //For vx
       magnitude[0] = originalValues[finalX][finalY][2];
       //for vy
       magnitude[1] = originalValues[finalX][finalY][3];
         
        return magnitude;
    }
    
    /**
     * 
     * @param gl 
     */
    @Override public void visualize(GL gl) {
        //if the checkbox visible is not checked
        if (!getVisible()) {
            // don't do anything when this renderer is not visible
            return;
        }
        int i, j;
        arrayGeneration();
        
        //DIM = number of vector on each column and on each row
        double/*fftw_real*/ wn = getWinWidth() / (double) nbX;   // Grid cell width
        double/*fftw_real*/ hn = getWinHeight() / (double) nbY;  // Grid cell heigh
        if( wn<15 || hn<15 ){ SLICES=4; STACKS=4;
        }else{ SLICES=9; STACKS=9; }
        // Enable lighting in GL.
        // Set light parameters.
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lPosition, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, lColorAmbient, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, lColorSpecular, 0);
        GLUquadric ellipsoid = Visualization.glu.gluNewQuadric();
        gl.glEnable(GL.GL_LIGHT0);
        gl.glEnable(GL.GL_LIGHTING);
        //for all lines and columns
        gl.glRotated( rotatePlaneDegrees , 0, 1, 0);
        for (i = 1; i < DIM+1; i++) {
            for (j = 1; j < DIM+1; j++) {
                double x = i * wn;
                double y = j * hn;
                if( x>getWinWidth() || y>getWinHeight() ) continue;
                double magnitude[] = nearestNeighbour(originalValues, x, y);
                float[] color = direction_to_color(gl, (float) magnitude[0], (float) magnitude[1] );
                // Set material properties.
                gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, color, 0);
                gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, color, 0);
                gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 0.3f);
                // Draw sphere (possible styles: FILL, LINE, POINT).
                Visualization.glu.gluQuadricDrawStyle(ellipsoid, GLU.GLU_FILL);
                Visualization.glu.gluQuadricNormals(ellipsoid, GLU.GLU_SMOOTH);
                Visualization.glu.gluQuadricOrientation(ellipsoid, GLU.GLU_OUTSIDE);
                gl.glPushMatrix();
                    gl.glTranslatef((float)(i * wn), (float)(j * hn), 0);
                    double xx=magnitude[0], yy=magnitude[1], angle=Math.toDegrees( Math.atan2(yy, xx) ),
                            m=Math.sqrt(magnitude[0]*magnitude[0]+ magnitude[1]*magnitude[1]);
                    if( yy>0d ) gl.glRotated( angle , 1, 0, 0);
                    if( yy<0d ) gl.glRotated( angle , -1, 0, 0);
                    if( xx>0d ) gl.glRotated( 90+angle , 0, 1, 0);
                    if( xx<0d ) gl.glRotated( 90+angle , 0, 1, 0);
                    if( enableClamping ){
                        if( (Math.abs(xx)*vec_scale)>wn/3 ) xx=(wn/(3*vec_scale));
                        if( (Math.abs(yy)*vec_scale)>hn/3 ) yy=(hn/(3*vec_scale));
                        if( m*vec_scale>wn*hn ) m=(wn*hn)/(4*vec_scale);
                    }
                    gl.glScalef( (float)(Math.abs(xx)*vec_scale), (float)(Math.abs(yy)*vec_scale), (float)m*vec_scale);
                    Visualization.glu.gluSphere(ellipsoid, RADIUS, SLICES, STACKS);
                gl.glPopMatrix();
            }
        }
        gl.glDisable(GL.GL_LIGHTING);
        Visualization.glu.gluDeleteQuadric(ellipsoid);
    }
    
}
